// Compile with: gcc tcpserver.c -o tcpserver
//
// Implement tcp server below.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <wait.h>

#define IP "0.0.0.0"
#define PORT 8080
#define BUFFER_SIZE 1024
#define MAX 80

void forkDoSystem(const char *cmd);

int main(int argc, char *argv[])
{
    int server_fd, new_socket, valread;
    struct sockaddr_in address;
    int opt = 1;
    int addrlen = sizeof(address);

    char buffer[BUFFER_SIZE] = {0};
    char *hello = "You have reached the server\n";

    // Creating socket file descriptor
    if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) // AF_INET: IPv4, SOCK_STREAM: TCP, 0: IP
    {
        perror("socket failed");
        exit(EXIT_FAILURE);
    }

    address.sin_family = AF_INET;            // IPv4
    address.sin_addr.s_addr = inet_addr(IP); // IP address
    address.sin_port = htons(PORT);          // port

    // bind socket to IP and port
    printf("Attemping to bind() server to %s:%d \n", IP, PORT);
    if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) // bind socket to IP and port
    {
        perror("bind failed");
        exit(EXIT_FAILURE);
    }

    // listen for connections
    printf("Server is listening for a client!\n");
    if (listen(server_fd, MAX) < 0) // listen for connections on the socket
    {
        perror("listen");
        exit(EXIT_FAILURE);
    }

    // accept connection from client
    do
    {
        if ((new_socket = accept(server_fd, (struct sockaddr *)&address, (socklen_t *)&addrlen)) < 0) // accept connection from client
        {
            perror("accept");
            exit(EXIT_FAILURE);
        }

        printf("Client has joined: %d\n", new_socket);
        send(new_socket, hello, strlen(hello), 0); // send message to client
        printf("> ");
        do
        {
            valread = read(new_socket, buffer, BUFFER_SIZE); // read infromation received into the buffer
            buffer[valread] = '\0';
            if (buffer[valread - 1] == '\n')
            {
                buffer[valread - 1] = '\0';
            }
            if (strcmp(buffer, "exit") == 0)
            {
                close(new_socket);
                break;
            }
            printf("%s\n", buffer);
            forkDoSystem(buffer);
        } while (valread > 0);
    } while (1);

    close(server_fd);

    return 0;
}

void forkDoSystem(const char *cmd)
{
    pid_t pid = fork();
    if (pid == 0)
    {
        system(cmd);
        exit(0);
    }
    else if (pid > 0)
    {
        wait(NULL);
    }
    else
    {
        perror("fork");
        exit(EXIT_FAILURE);
    }
}
